package com.cwd.arm.domain.service.msg;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.cwd.arm.common.enums.MsgTypeEnum;
import com.cwd.arm.common.util.SendSmsUtil;
import com.cwd.arm.domain.entity.base.MsgReEntity;
import com.cwd.arm.domain.util.PoToEntityUtil;
import com.cwd.arm.infrastructure.dao.*;
import com.cwd.arm.infrastructure.po.*;
import com.cwd.arm.infrastructure.query.MsgDaoQuery;
import com.cwd.arm.infrastructure.query.ProjectDaoQuery;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by yan on 22-2-19.
 */
@Service
@Slf4j
public abstract class MsgAppService {

    @Autowired
    private MsgDao msgDao;

    @Autowired
    private MsgRecipientDao msgRecipientDao;

    @Autowired
    private ProjectDao projectDao;

    @Autowired
    private ProjectReceiveDirectorDao projectReceiveDirectorDao;

    @Autowired
    private SendSmsUtil sendSmsUtil;

    @Autowired
    private UserDao userDao;

    /**
     * 新增消息
     */
    public void addRateWarnMsg() {
        List<MsgReEntity> msgReEntityList = getMsgReEntityList();
        List<MsgPo> oldMsgPoList = getUnCancelMsgPoList();
        Map<Long, MsgPo> oldMsgMap = oldMsgPoList.stream().collect(Collectors.toMap(MsgPo::getReId, Function.identity()));
        //待新增消息
        List<MsgPo> msgPoList = msgReEntityList.stream()
                .filter(msgReEntity -> needAddMsg(oldMsgMap, msgReEntity))
                .map(msgReEntity -> convertToMsgPo(msgReEntity))
                .collect(Collectors.toList());
        //保存消息
        msgDao.saveBatch(msgPoList);
        //保存消息接收人
        for (MsgPo msgPo : msgPoList) {
            List<Long> newRecipientIdList = getNewRecipientIdList(msgPo.getReId());
            List<MsgRecipientPo> addMsgRecipientPoList = buildMsgRecipientPoList(msgPo.getId(), newRecipientIdList);
            msgRecipientDao.saveBatch(addMsgRecipientPoList);
        }
    }

    /**
     * 取消消息
     */
    public void cancelRateWarnMsg() {
        List<MsgPo> msgPoList = getUnCancelMsgPoList();
        for (MsgPo msgPo : msgPoList) {
            MsgReEntity msgReEntity = getMsgReEntity(msgPo.getReId());
            if (!msgReEntity.isMatch(getMsgTypeEnum())) {
                msgPo.setHasCancel(true);
                msgDao.updateById(msgPo);
            }
        }
    }

    /**
     * 发送消息
     */
    public void sendMsg() throws Exception {
        List<MsgPo> msgPoList = getUnCancelMsgPoList();
        for (MsgPo msgPo : msgPoList) {
            List<MsgRecipientPo> msgRecipientPoList = msgRecipientDao.selectByMsgId(msgPo.getId());
            List<UserPo> userPoList = msgRecipientPoList.stream().map(po -> userDao.getById(po.getId())).filter(userPo -> hasPhone(userPo)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(userPoList)) {
                for (UserPo userPo : userPoList) {
                    sendSmsUtil.send(getMsgTypeEnum().getTemplateCode(), userPo.getPhone(), msgPo.getMsgParam());
                }
            }
        }
    }

    private boolean hasPhone(UserPo po) {
        if (StringUtils.isNotEmpty(po.getPhone())) {
            return true;
        }
        return false;
    }

    /**
     * 消息类型
     *
     * @return
     */
    protected abstract MsgTypeEnum getMsgTypeEnum();

    /**
     * 根据关联对象id查询接收人
     *
     * @param reId
     * @return
     */
    protected List<Long> getNewRecipientIdList(Long reId) {
        List<ProjectReceiveDirectorPo> poList = projectReceiveDirectorDao.selectListByProjectId(reId);
        return poList.stream().map(ProjectReceiveDirectorPo::getReceiveDirectorId).collect(Collectors.toList());
    }

    /**
     * 查询消息关联对象
     *
     * @param reId
     * @return
     */
    protected MsgReEntity getMsgReEntity(Long reId) {
        ProjectPo po = projectDao.getById(reId);
        return PoToEntityUtil.poToEntity(po);
    }

    /**
     * 查询所有的消息关联对象
     *
     * @return
     */
    protected List<MsgReEntity> getMsgReEntityList() {
        List<ProjectPo> projectPoList = projectDao.getUnCloseProjectList(new ProjectDaoQuery());
        return PoToEntityUtil.poToProjectEntityList(projectPoList);
    }

    private void saveMsgRecipient(MsgPo oldMsgPo) {
        List<MsgRecipientPo> oldRecipientPoList = msgRecipientDao.selectByMsgId(oldMsgPo.getId());
        List<Long> oldRecipientIdList = oldRecipientPoList.stream().map(MsgRecipientPo::getRecipientId).collect(Collectors.toList());
        List<Long> newRecipientIdList = getNewRecipientIdList(oldMsgPo.getReId());
        List<Long> delRecipientIdList = getNotExistList(oldRecipientIdList, newRecipientIdList);
        msgRecipientDao.removedByRecipientIdsAndMsgId(oldMsgPo.getId(), delRecipientIdList);
        List<Long> addRecipientIdList = getNotExistList(newRecipientIdList, oldRecipientIdList);
        List<MsgRecipientPo> addMsgRecipientPoList = buildMsgRecipientPoList(oldMsgPo.getId(), addRecipientIdList);
        msgRecipientDao.saveBatch(addMsgRecipientPoList);
    }

    /**
     * 查找不存在2中的1
     *
     * @param recipientIdList1
     * @param recipientIdList2
     * @return
     */
    private List<Long> getNotExistList(List<Long> recipientIdList1, List<Long> recipientIdList2) {
        return recipientIdList1.stream()
                .filter(id -> !hasExist(recipientIdList2, id)).collect(Collectors.toList());
    }

    private List<MsgRecipientPo> buildMsgRecipientPoList(Long msgId, List<Long> recipientIdList) {
        return recipientIdList.stream().map(id -> buildMsgRecipientPo(msgId, id)).collect(Collectors.toList());
    }

    private MsgRecipientPo buildMsgRecipientPo(Long msgId, Long recipientId) {
        MsgRecipientPo msgRecipientPo = new MsgRecipientPo();
        msgRecipientPo.setMsgId(msgId);
        msgRecipientPo.setRecipientId(recipientId);
        return msgRecipientPo;
    }

    private boolean hasExist(List<Long> newRecipientIdList, Long oldRecipientId) {
        Long findId = newRecipientIdList.stream().filter(id -> id.compareTo(oldRecipientId) == 0).findAny().orElse(null);
        if (findId == null) {
            return false;
        }
        return true;
    }

    private MsgPo convertToMsgPo(MsgReEntity msgReEntity) {
        MsgPo msgPo = new MsgPo();
        msgPo.setMsgType(getMsgTypeEnum().getCode());
        msgPo.setContent(msgReEntity.getContent(getMsgTypeEnum()));
        msgPo.setMsgParam(msgReEntity.getMsgParam(getMsgTypeEnum()));
        msgPo.setReId(msgReEntity.getId());
        return msgPo;
    }

    private List<MsgPo> getUnCancelMsgPoList() {
        MsgDaoQuery msgDaoQuery = new MsgDaoQuery();
        msgDaoQuery.setHasCancel(false);
        msgDaoQuery.setMsgType(getMsgTypeEnum().getCode());
        return msgDao.selectByQuery(msgDaoQuery);
    }

    /**
     * 是否需要新增对象
     *
     * @param oldMsgMap   原来的未取消的消息map
     * @param msgReEntity 该类消息关联的对象
     * @return
     */
    private boolean needAddMsg(Map<Long, MsgPo> oldMsgMap, MsgReEntity msgReEntity) {
        if (msgReEntity.isMatch(getMsgTypeEnum())) {
            MsgPo oldMsgPo = oldMsgMap.get(msgReEntity.getId());
            if (oldMsgPo == null) {
                return true;
            } else {//已有信息更新接收人
                saveMsgRecipient(oldMsgPo);
                return false;
            }
        }
        return false;
    }

}
